# coding=utf-8
# 数据库连接类
# 设计思路是数据库连接保存在本类中
# 单独进行管理，和数据库操作逻辑分离
# 提供最基础的数据库操作
# 可以使用对于不同种类数据库提供分别的连接和基础操作

from rs_label.util.parameter import Para

class Connection(object):
    """
    数据库连接类
    """

    def __init__(self, db_type):
        """
        初始化函数，定义当前连接所用的数据库管理软件
        """
        self.__db_type = db_type
        # 数据库名跳转打开连接函数的dict
        self.__db_open_conn_func = {"sqlite3": self.sqlite_open_conn,
                                    "mysql": self.mysql_open_conn}
        # 数据库连接是否打开标记
        # 防止未打开的时候连接数据库造成错误
        # 1代表没有打开 0代表已经打开
        self.__open_flag = 1

    def open_conn(self, **options):
        """
        启动连接
        :param options:打开数据库连接需要的参数
        :return:返回值为0代表数据连接打开成功
                返回值为1代表数据连接打开失败
        """
        # 返回值为0代表数据连接打开成功
        # 返回值为1代表数据连接打开失败
        # 将数据库打开情况返回上一级
        self.__open_flag = self.__db_open_conn_func.get(self.__db_type)(options)
        return self.__open_flag



    def close_conn(self):
        """
        关闭数据库连接
        :return:
        """
        # 设置打开标记为未打开
        self.__open_flag = 1
        self.__conn.close()


    def __del__(self):
        """
        析构函数，方式没有显示关闭数据库连接，造成资源闲置
        :return:
        """
        self.__conn.close()
        # print("close connection in del func")

    @property
    def db_type(self):
        """
        本连接数据库名称
        :return:
        """
        return self.__db_type

    @property
    def conn(self):
        """
        数据库连接
        :return: 返回连接对象
        """
        # 判断数据库连接是否已经打开
        if self.__open_flag == 0:
            return self.__conn
        else:
            # 如果没有打开，则返回空值
            return None

    # --------------------------------各种不同数据库打开连接函数---------------------
    # 实际操作的函数式私有函数
    def sqlite_open_conn(self, options):
        """
        sqlite数据库打开连接
        :param options:连接参数，dict类型
                        只需要一个参数"db_path"，代表数据库所在位置
        :return:返回0代表连接成功
                返回1代表失败
        """
        import sqlite3
        # 默认为Para中的连接
        if "db_path" in options:
            db_path = options["db_path"]
        else:
            configFileName = "/usr/data/remote_sensing/crowdsourcing_label/tmp/para.config"
            para = Para(configFileName)
            db_path = para.db_name

        # 打开sqlite数据库连接
        self.__conn = sqlite3.connect(db_path)
        return 0



    def mysql_open_conn(self, options):
        """
        mysql数据库打开连接
        :param options:
        :return:
        """
        pass

    def fetch_data_from_db(self, sql, **options):
        """
        根据sql语句，从数据库中获取数据
        数据库即为实例链接
        :param sql: sql语句
        :param options: 可选参数
        :return: 返回取回的内容，为List类型
                如果产生异常，返回None
        """
        if self.__open_flag == 1:
            return None
        try:
            cursor = self.__conn.execute(sql)
            res = list()
            for row in cursor:
                # row是一个tuple
                res.append(row)
                print(type(row), row)
            return res
        except Exception as e:
            print("db error:", e)


    def execute_in_db(self, sql, **options):
        """
        执行sql语句(无取回内容)
        数据库即为实例链接
        :param sql:
        :param options:
        :return: 执行成功返回0
                失败返回None
        """
        if self.__open_flag == 1:
            return None
        try:
            self.__conn.execute(sql)
            self.__conn.commit()
        except Exception as e:
            print("db error:", e)

    def executemany_in_db(self, sql, values, **options):
        """
        高效多次执行同一sql语句(无取回内容)
        sql中实际数据在values中
        数据库即为实例链接
        :param sql:缺失数据的sql语句
        :param values: sql中缺失的实际数据
        :param options:
        :return: 执行成功返回0
                失败返回None
        """
        if self.__open_flag == 1:
            return None
        try:
            self.__conn.executemany(sql, values)
            self.__conn.commit()
        except Exception as e:
            print(e)


# 对于数据库连接类进行测试
def main():
    c = Connection()
    res = c.open_conn(db_path=Para.db_name)
    print(res)
    l = c.fetch_data_from_db("select * from GF2_shanghai_label_name")
    print(l)
    c.close_conn()
    print(c.conn)

if __name__ == "__main__":
    main()

